#===--------------------------------------------------------*- Makefile -*--===#
#
#                     The KLEE Symbolic Virtual Machine
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
# This files defines the rules used for the bitcode build system. They are
# inspired by LLVM's old Makefile build system.
#===------------------------------------------------------------------------===#
.PHONY: all build_at_level clean debug_vars force

CURRENT_DIR:= $(shell pwd)

# Sanity checks
ifndef LEVEL
  $(error LEVEL must be defined)
endif

ifndef LLVMCC
  $(error Makefile.cmake.bitconfig.config must be included)
endif

# Any changes to the files listed here will trigger a rebuild of the sources
ADDITIONAL_BUILD_DEPS := $(CURRENT_DIR)/Makefile.cmake.bitcode \
                         $(RUNTIME_CMAKE_BINARY_DIR)/Makefile.cmake.bitcode.config \
                         $(RUNTIME_CMAKE_BINARY_DIR)/Makefile.cmake.bitcode.rules \
                         $(RUNTIME_CMAKE_BINARY_DIR)/Makefile.cmake.bitcode

# Handle VERBOSE
VERBOSE ?= 0
ifneq ($(VERBOSE),0)
  Verb :=
else
  Verb := @
endif
#
# Handle build mode flags
ifeq ($(IS_RELEASE),1)
LLVMCC.Flags += -O2
else
LLVMCC.Flags += $(O0OPT)
endif

# Handle assertion flags
ifeq ($(ASSERTIONS_ENABLED),0)
LLVMCC.Flags += -DNDEBUG
endif

# Handle debug symbol flags
ifneq ($(DEBUG_SYMBOLS_ENABLED),0)
LLVMCC.Flags += -g
endif

ifdef DIRS
# all directory recursion target
all::
	$(Verb) for dir in $(DIRS); do \
		($(MAKE) -C $$dir -f Makefile.cmake.bitcode) || exit 1; \
	done

clean::
	$(Verb) for dir in $(DIRS); do \
		($(MAKE) -C $$dir -f Makefile.cmake.bitcode $@) || exit 1; \
	done
else
# Build sources

all:: build_at_level

# Compute the directory to find sources
# Note: Use of $(realpath) is to resolve any symlinks
DIR_SUFFIX := $(subst $(realpath $(RUNTIME_CMAKE_BINARY_DIR)),,$(realpath $(CURRENT_DIR)))
SRC_DIR := $(abspath $(ROOT_SRC)/$(DIR_SUFFIX))
# Sanity check
ifeq ($(realpath $(SRC_DIR)),)
$(error SRC_DIR "$(SRC_DIR)" does not exist)
endif

# Compute the directory to put build files
LOCAL_BUILD_DIR := $(abspath $(ROOT_OBJ)/$(DIR_SUFFIX))

C_SRCS := $(sort $(shell echo $(SRC_DIR)/*.c))

# Sanity check: Make sure at least one source file was found
ifneq ($(strip $(filter %*.c,$(C_SRCS))),)
$(error Failed to find C source files in $(SRC_DIR))
endif

C_SRCS_NO_DIR := $(notdir $(C_SRCS))
BC_FILES_NO_DIR := $(C_SRCS_NO_DIR:.c=.bc)
BC_FILES := $(addprefix $(LOCAL_BUILD_DIR)/,$(BC_FILES_NO_DIR))

# Path to file that stores the flags used for LLVMCC.
# If the build flags are changed this should trigger
# a change to the this file which will force a recompile
# of all sources
LLVMCC_FLAGS_FILE := $(LOCAL_BUILD_DIR)/LLVMCC_FLAGS

# Path to file that stores list of bc files that constitute
# bitcode archive or bitcode module. If the list of bitcode
# files changes this should trigger a rebuild of the bitcode
# archive or module
BC_FILE_LIST_FILE := $(LOCAL_BUILD_DIR)/BC_FILE_LIST

# All bitcode files have these additional dependencies
$(BC_FILES) : $(ADDITIONAL_BUILD_DEPS) $(LLVMCC_FLAGS_FILE)

# Include dependency information generated by previous
# compiler invocations if they exist
-include $(BC_FILES:.bc=.dep)

# Pattern rule to build bitcode files
$(LOCAL_BUILD_DIR)/%.bc : $(SRC_DIR)/%.c
	@echo "LLVMCC ($(RUNTIME_CONFIG_STRING)) $<"
	$(Verb) $(MKDIR) -p $(LOCAL_BUILD_DIR)
	$(Verb) $(LLVMCC) $(LLVMCC.Flags) $(LLVMCC.Warnings) $< -c -o $@ -MP -MMD -MF $(LOCAL_BUILD_DIR)/$*.dep

# $(LLVMCC_FLAGS_FILE) depends on `force` which will force the rule to
# rerun every build. However the rule will only update the file when the
# compile flags change which means we will trigger a rebuild when the compile
# flags change.
LLVMCC_FLAGS_FOR_FILE := $(LLVMCC) $(LLVMCC.Flags) $(LLVMCC.Warnings)
$(LLVMCC_FLAGS_FILE): force
	$(Verb) $(MKDIR) -p "$(dir $(LLVMCC_FLAGS_FILE))"
	$(Verb)echo "$(LLVMCC_FLAGS_FOR_FILE)" | $(CMP) -s - $@ || echo "$(LLVMCC_FLAGS_FOR_FILE)" > $@

# $(BC_FILE_LIST_FILE) depends on `force` which will force rule to
# rerun every build. However the rule will only update the file when
# the list of bc files changes which means we should only trigger a rebuild
# or the bitcode archive/module when the list of bc files changes
$(BC_FILE_LIST_FILE): force
	$(Verb) $(MKDIR) -p "$(dir $(BC_FILE_LIST_FILE))"
	$(Verb)echo "$(BC_FILES_NO_DIR)" | $(CMP) -s - $@ || echo "$(BC_FILES_NO_DIR)" > $@

clean::
	@echo "Removing bitcode files"
	$(Verb) $(RM) -f $(BC_FILES)
	@echo "Removing dependency files"
	$(Verb) $(RM) -f $(BC_FILES:.bc=.dep)

ifdef ARCHIVE_NAME
ARCHIVE_FILE := $(ARCHIVE_DEST)/lib$(ARCHIVE_NAME).bca

build_at_level:: $(ARCHIVE_FILE)

# Rule for building LLVM bitcode archive
# NOTE: Dependency on $(BC_FILE_LIST_FILE) is to force
# rebuild when list of BC_FILES changes.
$(ARCHIVE_FILE): $(BC_FILES) $(BC_FILE_LIST_FILE)
	$(Verb) $(MKDIR) -p $(ARCHIVE_DEST)
	@echo "Creating LLVM archive $@"
	$(Verb) $(RM) -f $@
	$(Verb)$(LLVM_AR) rcs $@ $(BC_FILES)

clean::
	@echo "Removing LLVM bitcode archive $(ARCHIVE_FILE)"
	$(Verb) $(RM) -f $(ARCHIVE_FILE)
else
$(error ARCHIVE_NAME must be defined)
endif # ARCHIVE_NAME


endif # end not ifdef DIRS

debug_vars:
	@echo "********************************************************************************"
	@echo "Makefile variables for debugging"
	@echo "********************************************************************************"
	@echo "ARCHIVE_FILE := $(ARCHIVE_FILE)"
	@echo "ASSERTIONS_ENABLED := $(ASSERTIONS_ENABLED)"
	@echo "BC_FILES := $(BC_FILES)"
	@echo "BC_FILES_NO_DIR := $(BC_FILES_NO_DIR)"
	@echo "BC_FILE_LIST_FILE := $(BC_FILE_LIST_FILE)"
	@echo "BUILD_ROOT := $(BUILD_ROOT)"
	@echo "C_SRCS := $(C_SRCS)"
	@echo "CURRENT_DIR := $(CURRENT_DIR)"
	@echo "DEBUG_SYMBOLS_ENABLED := $(DEBUG_SYMBOLS_ENABLED)"
	@echo "IS_RELEASE := $(IS_RELEASE)"
	@echo "LOCAL_BUILD_DIR := $(LOCAL_BUILD_DIR)"
	@echo "LLVMCC := $(LLVMCC)"
	@echo "LLVMCC_FLAGS_FILE := $(LLVMCC_FLAGS_FILE)"
	@echo "LLVMCC.Flags := $(LLVMCC.Flags)"
	@echo "LLVMCC.ExtraFlags := $(LLVMCC.ExtraFlags)"
	@echo "LLVMCC.Warnings := $(LLVMCC.Warnings)"
	@echo "ROOT_OBJ := $(ROOT_OBJ)"
	@echo "RUNTIME_CONFIG_STRING := $(RUNTIME_CONFIG_STRING)"
	@echo "SRC_DIR := $(SRC_DIR)"
	@echo "VERBOSE := $(VERBOSE)"
